package com.yswy.backstage.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableList;
import com.yswy.backstage.dto.req.*;
import com.yswy.backstage.dto.res.*;
import com.yswy.backstage.service.IAdminService;
import com.yswy.common.enums.IsEnum;
import com.yswy.common.utils.AES128Util;
import com.yswy.domain.common.BasePojo;
import com.yswy.domain.entity.user.*;
import com.yswy.domain.mapper.user.*;
import com.yswy.domain.vo.gld.filter.RolePageFilter;
import com.yswy.domain.vo.gld.filter.UserPageFilter;
import com.yswy.domain.vo.gld.filter.RolePageResVO;
import com.yswy.domain.vo.gld.filter.UserPageResVO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import static com.yswy.backstage.utils.CrudUtils.*;
import static java.lang.Long.valueOf;

@Slf4j
@Service
public class IAdminServiceImpl implements IAdminService {

    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private RolePermissionMapper rolePermissionMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private UserMapper userMapper;

    @Override
    public List<MenuTreeResVO> menuTree(Long id, Integer idType) {
        Assert.state(null != id && null != idType, "参数不能为空");
        AtomicReference<List<Integer>> roleIds = new AtomicReference<>();
        switch (idType) {
            case 1:
                List<UserRole> mUserRoles = selectList(userRoleMapper, m -> m.eq(UserRole::getUserId, id));
                roleIds.set(map(mUserRoles, UserRole::getRoleId));
                break;
            case 2:
                roleIds.set(ImmutableList.of(Math.toIntExact(id)));
                break;
            default:
                throw new IllegalStateException("类型错误");
        }
        if (CollectionUtils.isEmpty(roleIds.get())) {
            return new ArrayList<>();
        }
        List<RolePermission> mRolePermission = selectList(rolePermissionMapper, m -> m.in(RolePermission::getRoleId, roleIds.get()));
        if (CollectionUtils.isEmpty(mRolePermission)) {
            return new ArrayList<>();
        }
        List<Integer> permissionIds = map(mRolePermission, RolePermission::getPermissionId);
        List<MenuTreeResVO> permissions = list(permissionMapper,
                m -> m.in(Permission::getId, permissionIds).eq(Permission::getIsDel, IsEnum.NOT_IS.getCode()).eq(Permission::getFreezingSatus, 0).notIn(Permission::getPermissionType, 3, 4),
                MenuTreeResVO::new);
        if (CollectionUtils.isEmpty(permissions)) {
            return new ArrayList<>();
        }
        Comparator<MenuTreeResVO> comparing = Comparator.comparing(MenuTreeResVO::getOrderBy);

        Map<Object, List<MenuTreeResVO>> permissionsMap = groupSorted(permissions, MenuTreeResVO::getPId, comparing);
        List<MenuTreeResVO> tree = treeSorted(permissions, c -> c.setChildren(permissionsMap.get(c.getId())), f -> null == f.getPId() || 0 == f.getPId(), comparing);
        tree = peek(tree, p -> {
            List<MenuTreeResVO> children = p.getChildren();
            if (CollectionUtils.isNotEmpty(children)) {
                p.setAlwaysShow(true);
                p.setChildren(peek(children, pSon -> pSon.setAlwaysShow(CollectionUtils.isNotEmpty(pSon.getChildren()))));
            }
        });
        return tree;
    }

    @Override
    public List<RuleTreeResVO> ruleTree(Long menuId, Long optionId) {
        List<UserRole> userRoles = selectList(userRoleMapper, s -> s.eq(UserRole::getUserId, optionId));
        List<Integer> roleIds = map(userRoles, UserRole::getRoleId);
        List<RolePermission> rolePermissions = selectList(rolePermissionMapper, s -> s.in(RolePermission::getRoleId, roleIds));
        List<Integer> permissionIds = map(rolePermissions, RolePermission::getPermissionId, true);
        List<Permission> permissions = selectList(permissionMapper, s -> s
                .in(Permission::getId, permissionIds)
                .select(Permission::getId, Permission::getPId, Permission::getPermissionName, Permission::getName, Permission::getPath)
                .eq(Permission::getIsDel, IsEnum.NOT_IS.getCode())
                .eq(Permission::getFreezingSatus, 0)
                .eq(Permission::getPermissionType, 3)
                .eq(null != menuId, Permission::getPId, menuId));
        Map<Object, List<Permission>> group = group(permissions, Permission::getPId);
        return group.entrySet().stream().map(m ->
                new RuleTreeResVO(Long.valueOf(m.getKey().toString()), map(m.getValue(), m1 -> new RuleTreeChildrenResVO(m1.getName(), m1.getPath())))
        ).collect(Collectors.toList());
    }

    @Override
    public List<PermissionConfigTreeResVO> permissionConfigTree(PermissionConfigTreeReqVO req, Long optionId) {
        Integer roleId = req.getRoleId();
        Integer userId = req.getUserId();
        List<Integer> roleIds = null == req.getRoleId() ? ImmutableList.of() : ImmutableList.of(roleId);
        AtomicReference<List<Integer>> selectPermissionIds = new AtomicReference<>(new ArrayList<>());
        if (null != userId) {
            List<UserRole> userRoles = selectList(userRoleMapper, s -> s.select(UserRole::getUserId, UserRole::getRoleId).eq(UserRole::getUserId, userId));
            List<Integer> map = map(userRoles, UserRole::getRoleId);
            roleIds.addAll(map);
        }
        if (CollectionUtils.isNotEmpty(roleIds)) {
            List<RolePermission> roleList = selectList(rolePermissionMapper, s -> s.select(RolePermission::getRoleId, RolePermission::getPermissionId).in(RolePermission::getRoleId, roleIds));
            selectPermissionIds.set(map(roleList, RolePermission::getPermissionId));
        }

//        List<PermissionConfigTreeResVO> list = list(permissionMapper, s -> {
//                s.eq(Permission::getIsDel, IsEnum.NOT_IS.getCode()).eq(Permission::getFreezingSatus, false);
//        }, f -> !f.getId().toString().startsWith("1"), m -> {
//            boolean isUsed = selectPermissionIds.get().contains(Math.toIntExact(m.getId()));
//            PermissionConfigTreeResVO result = new PermissionConfigTreeResVO(m.getId(), m.getPId(), null == m.getOrderBy() ? 0 : m.getOrderBy(), m.getPermissionName(), isUsed);
//            return result;
//        });
        List<PermissionConfigTreeResVO> list = list(permissionMapper, s -> {
                s.eq(Permission::getIsDel, IsEnum.NOT_IS.getCode()).eq(Permission::getFreezingSatus, false);
        }, m -> {
            boolean isUsed = selectPermissionIds.get().contains(Math.toIntExact(m.getId()));
            PermissionConfigTreeResVO result = new PermissionConfigTreeResVO(m.getId(), m.getPId(), null == m.getOrderBy() ? 0 : m.getOrderBy(), m.getPermissionName(), isUsed);
            return result;
        });
        Comparator<PermissionConfigTreeResVO> comparing = Comparator.comparing(PermissionConfigTreeResVO::getOrderBy);
        Map<Object, List<PermissionConfigTreeResVO>> permissionMap = groupSorted(list, PermissionConfigTreeResVO::getPid, comparing);
        return treeSorted(list, c -> c.setChildren(permissionMap.get(c.getId())), f -> null == f.getPid() || 0 == f.getPid(), comparing);
    }

    @Override
    public void permissionFreezing(Long id, boolean freezingSatus, Long optionId) {
        // 校验用户数据完整性
        if (!freezingSatus) {
            // 有无角色
//            Integer integer = selectCount(permissionMapper, w -> w.eq(Permission::getId, id));
//            Assert.state(integer > 0, "启用失败，未设置角色");
        }
        Permission bo = selectById(permissionMapper, id);
        bo.setFreezingSatus(freezingSatus);
        createOrUpdate(permissionMapper, id, bo, null);
    }

    @Override
    public Page<PermissionPageResVO> permissionPage(PermissionPageFilter filter, Long optionId) {
        List<PermissionPageResVO> list = list(permissionMapper, s -> {
            s.eq(Permission::getIsDel, IsEnum.NOT_IS.getCode())
                    .in(Permission::getPermissionType, Arrays.asList(1, 2))
                    .likeRight(StringUtils.isNotEmpty(filter.getPermissionName()), Permission::getPermissionName, filter.getPermissionName())
                    .eq(null != filter.getFreezingSatus(), Permission::getFreezingSatus, filter.getFreezingSatus())
                    .and(StringUtils.isNotEmpty(filter.getKeyWord()), a -> a.like(Permission::getPermissionName, filter.getKeyWord()));
        }, f -> !f.getId().toString().startsWith("1"), m -> BeanUtil.copyProperties(m, PermissionPageResVO.class));
        Comparator<PermissionPageResVO> comparing = Comparator.comparing(PermissionPageResVO::getOrderBy);
        Map<Object, List<PermissionPageResVO>> permissionMap = groupSorted(list, PermissionPageResVO::getPId, comparing);
        List<PermissionPageResVO> tree = treeSorted(list, c -> c.setChildren(permissionMap.get(c.getId())), f -> null == f.getPId() || 0 == f.getPId(), comparing);
        return page(tree, filter);
    }

    @Override
    public void permissionCreate(PermissionOptionReqVO req, Long optionId) {
        long pId = null == req.getPId() ? 0L : req.getPId();
        Permission bo = BeanUtil.copyProperties(req, Permission.class);
        Long newId;

        List<Permission> permissions = selectList(permissionMapper, s -> {
            s.eq(Permission::getPId, pId).orderByDesc(Permission::getId);
        });
        if (CollectionUtils.isEmpty(permissions)) {
            if (pId > 100) {
                return;
            }
            newId = pId * 100;
        } else {
            newId = permissions.get(0).getId();
        }

        bo.setId(1L + newId);
        bo.setFreezingSatus(true);
        bo.create(optionId);
        createOrUpdate(permissionMapper, null, bo, vw -> vw.eq(Permission::getPermissionName, bo.getPermissionName()));
    }

    @Override
    public void permissionUpdate(PermissionOptionReqVO req, Long optionId) {
        Permission bo = BeanUtil.copyProperties(req, Permission.class);
        bo.update(optionId);
        createOrUpdate(permissionMapper, bo.getId(), bo, vw -> vw.eq(Permission::getPermissionName, bo.getPermissionName()).notIn(Permission::getId, bo.getId()));
    }

    @Override
    public void permissionDelete(Long id, Long optionId) {

    }

    @Override
    public Page<RolePageResVO> rolePage(RolePageFilter filter, Long optionId) {
        return page(roleMapper, filter, f -> {
            SFunction<Role, Date> column = (null == filter.getTimeType() || null == filter.getStaTime() || null == filter.getEndTime()) ? null :
                    filter.getTimeType() == 1 ? Role::getCreateTime : filter.getTimeType() == 2 ? Role::getUpdateTime : null;
            f.eq(BasePojo::getIsDel, IsEnum.NOT_IS.getCode())
                .like(StringUtils.isNotEmpty(filter.getRoleName()), Role::getRoleName, filter.getRoleName())
                .and(StringUtils.isNotEmpty(filter.getKeyWord()), a -> a.like(Role::getRoleName, filter.getKeyWord()))
                .eq(null != filter.getFreezingSatus(), Role::getFreezingSatus, filter.getFreezingSatus())
                .between(null != column, column, filter.getPageNum(), filter.getPageSize())
                .orderByDesc(Role::getId);
        }, result -> {

        }, m -> {
            RolePageResVO bo = BeanUtil.copyProperties(m, RolePageResVO.class);
            return bo;
        });
    }

    @Override
    public void roleFreezing(Long id, boolean freezingSatus, Long optionId) {
        // 校验用户数据完整性
        if (freezingSatus) {
            Integer integer = selectCount(userRoleMapper, w -> w.eq(UserRole::getRoleId, id));
            Assert.state(0 == integer, "禁用失败，用户使用中");
        } else {
            Integer integer = selectCount(rolePermissionMapper, s -> s.eq(RolePermission::getRoleId, id));
            Assert.state(0 < integer, "启用失败，未设置权限");
        }
        Role bo = selectById(roleMapper, id);
        bo.setFreezingSatus(freezingSatus);
        createOrUpdate(roleMapper, id, bo, null);
    }

    @Override
    public List<Role> roleList(String roleName, Long optionId) {
        return selectList(roleMapper, w -> w.like(StringUtils.isNotEmpty(roleName), Role::getRoleName, roleName).eq(Role::getFreezingSatus, IsEnum.NOT_IS.getCode()).eq(BasePojo::getIsDel, IsEnum.NOT_IS.getCode()));
    }

    @Override
    public void roleCreate(RoleOptionReqVO req, Long optionId) {
        Role bo = BeanUtil.copyProperties(req, Role.class);
        bo.setFreezingSatus(true);
        bo.create(optionId);
        createOrUpdate(roleMapper, null, bo, vw -> vw.eq(Role::getRoleName, req.getRoleName()));
        createRolePermissions(req.getPermissionIds(), bo.getId(), false);
    }

    @Override
    public void roleUpdate(RoleOptionReqVO req, Long optionId) {
        Role bo = BeanUtil.copyProperties(req, Role.class);
        bo.update(optionId);
        createOrUpdate(roleMapper, bo.getId(), bo, vw -> vw.eq(Role::getRoleName, bo.getRoleName()).notIn(Role::getId, bo.getId()));
        createRolePermissions(req.getPermissionIds(), bo.getId(), true);
    }

    private void createRolePermissions(List<Integer> permissionIds, Long roleId, boolean isDel) {
        List<Integer> permissionIdList = CollectionUtils.isNotEmpty(permissionIds) ? permissionIds : new ArrayList<>();
        List<Permission> permissions = selectList(permissionMapper, s -> s.select(Permission::getId).likeRight(Permission::getId, "1"));
        permissionIdList.addAll(map(permissions, m -> Math.toIntExact(m.getId())));
        if (isDel) {
            delete(rolePermissionMapper, w -> w.eq(RolePermission::getRoleId, roleId));
        }
        Collections.sort(permissionIdList);
        for (Integer permissionId : permissionIdList) {
            createOrUpdate(rolePermissionMapper, null, new RolePermission(null, Math.toIntExact(roleId), permissionId, new Date()));
        }
    }

    @Override
    public void roleDelete(Long id, Long optionId) {
        Integer count = selectCount(userRoleMapper, s -> s.eq(UserRole::getRoleId, id));
        Assert.isTrue(0 == count, "使用中，不可删除");
//        int i = roleMapper.deleteById(id);
        Role role = new Role();
        role.setId(id);
        role.setIsDel(1);
        createOrUpdate(roleMapper, id, role);

        // 删除用户-角色关系
        delete(userRoleMapper, w -> w.eq(UserRole::getRoleId, id));
//        // 删除角色-权限关系
//        delete(rolePermissionMapper, w -> w.eq(RolePermission::getRoleId, id));
    }

    @Override
    public Page<UserPageResVO> userPage(UserPageFilter filter, Long optionId) {
        AtomicReference<Map<Object, List<UserRole>>> userRoleMap = new AtomicReference<>();
        AtomicReference<Map<Long, String>> roleMap = new AtomicReference<>();
        return page(userMapper, filter, s -> {
            s.like(StringUtils.isNotEmpty(filter.getUserName()), User::getUserName, filter.getUserName())
                .like(StringUtils.isNotEmpty(filter.getUserPhone()), User::getUserPhone, filter.getUserPhone())
                .eq(null != filter.getFreezingSatus(), User::getFreezingSatus, filter.getFreezingSatus())
                .and(StringUtils.isNotEmpty(filter.getKeyWord()), a ->
                        a.like(User::getUserPhone, filter.getKeyWord())
                        .or(r -> r.like(User::getUserName, filter.getKeyWord())))
                    .orderByDesc(User::getId);
        }, r -> {
            List<Integer> ids = map(r, User::getId);
            List<UserRole> userRoles = selectList(userRoleMapper, w -> w.in(UserRole::getUserId, ids));
            if (CollectionUtils.isEmpty(userRoles)) {
                return;
            }
            List<Integer> roleIds = map(userRoles, UserRole::getRoleId);

            List<Role> roles = selectList(roleMapper, w -> w.in(Role::getId, roleIds));
            if (CollectionUtils.isEmpty(roles)) {
                return;
            }
            userRoleMap.set(group(userRoles, UserRole::getUserId));
            roleMap.set(collect(roles, Collectors.toMap(Role::getId, Role::getRoleName)));
        }, m -> {
            UserPageResVO bo = BeanUtil.copyProperties(m, UserPageResVO.class);
            try {
                bo.setPwd(AES128Util.decrypt(bo.getPwd()));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            if (null == userRoleMap.get()) {
                return bo;
            }
            List<UserRole> userRoles = userRoleMap.get().get(bo.getId());
            if (CollectionUtils.isEmpty(userRoles)) {
                return bo;
            }
            bo.setRoleNames(String.join(",", map(userRoles, m1 -> roleMap.get().get(valueOf(m1.getRoleId())), true)));
            bo.setRoleIds(map(userRoles, UserRole::getRoleId, true));
            return bo;
        });
    }

    @Override
    public void userFreezing(Long id, boolean freezingSatus, Long optionId) {
        // 校验用户数据完整性
        if (!freezingSatus) {
            // 有无角色
            Integer integer = selectCount(userRoleMapper, w -> w.eq(UserRole::getUserId, id));
            Assert.state(integer > 0, "启用失败，未设置角色");
        }
        User bo = selectById(userMapper, id);
        bo.setFreezingSatus(freezingSatus);
        createOrUpdate(userMapper, id, bo, null);
    }

    @Override
    public void userCreate(UserOptionReqVO req, Long optionId) {
        User bo = commonCreateOrUpdate(req, optionId, c -> {});
        insertRelationUserRole(bo.getId(), req.getRoleIds());
    }

    @Override
    public void userUpdate(UserOptionReqVO req, Long optionId) {
        User bo = commonCreateOrUpdate(req, optionId, c -> {
            User user = selectById(userMapper, c.getId());
            if (!user.getFreezingSatus()) {
                List<UserRole> userRoles = selectList(userRoleMapper, w -> w.eq(UserRole::getUserId, req.getId()));
                List<Integer> roleIds = map(userRoles, UserRole::getRoleId);
                Assert.state(new HashSet<>(req.getRoleIds()).containsAll(new HashSet<>(roleIds)), "该状态下不可修改角色信息");
            }
        });
        delete(userRoleMapper, w -> w.in(UserRole::getUserId, bo.getId()));
        insertRelationUserRole(bo.getId(), req.getRoleIds());
    }

    private User commonCreateOrUpdate(UserOptionReqVO req, Long userId, Consumer<User> userConsumer) {
        boolean isId = null != req.getId();
        User bo = BeanUtil.copyProperties(req, User.class);
        String encrypt = "";
        try {
            encrypt = AES128Util.encrypt(bo.getPwd());
        } catch (Exception e) {
            throw new RuntimeException("密码错误");
        }
        if (isId) {
            bo.setUpdateBy(userId.toString());
            bo.setUpdateTime(new Date());
        } else {
            bo.setFreezingSatus(true);
            bo.setCreateBy(userId.toString());
            bo.setCreateTime(new Date());
        }
        bo.setPwd(encrypt);
        userConsumer.accept(bo);
        createOrUpdate(userMapper, isId ? valueOf(bo.getId()) : null, bo, vw ->
            vw.eq(User::getUserPhone, bo.getUserPhone()).notIn(isId, User::getId, bo.getId()), "手机号重复");
        return bo;
    }

    private void insertRelationUserRole(Integer userId, List<Integer> roleIds) {
        if (CollectionUtils.isEmpty(roleIds)) {
            return;
        }
        List<Role> roles = roleMapper.selectBatchIds(roleIds);
        for (Role role : roles) {
            UserRole userRole = new UserRole(null, userId, Math.toIntExact(role.getId()), role.getRoleType(), new Date());
            userRoleMapper.insert(userRole);
        }
    }

    @Override
    public void userDelete(Long id, Long optionId) {
        User bo = new User();
//        bo.set
//        delete(userMapper, id);
//        createOrUpdate(userMapper, id, bo, vw -> {}, "手机号重复");
        // 删除用户-角色关系
//        delete(userRoleMapper, w -> w.eq(UserRole::getUserId, id));
    }

}
